<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>阶梯计提计算器</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        input:focus { outline: 2px solid #2563eb; }
        .settings-scroll { max-height: 35vh; overflow-y: auto; }
        .success-tip { color: #10b981; font-size: 0.75rem; margin: 0; animation: fadeInOut 3s ease forwards; }
        .error-tip { color: #ef4444; font-size: 0.75rem; margin: 0; }
        @keyframes fadeInOut { 0% { opacity: 0; } 20% { opacity: 1; } 80% { opacity: 1; } 100% { opacity: 0; } }
    </style>
</head>
<body class="bg-gray-100 p-4">
    <div class="max-w-3xl mx-auto space-y-4">
        <div class="bg-white rounded-lg shadow">
            <div id="settings-header" class="p-3 font-bold bg-gray-50 cursor-pointer flex justify-between">
                <span>计提规则设置</span>
                <span id="settings-icon">+</span>
            </div>
            <div id="settings-content" class="p-3 hidden settings-scroll">
                <div class="flex gap-2 mb-3">
                    <div class="flex-1">
                        <label class="block text-sm font-semibold mb-1">载货保底(元)</label>
                        <input type="number" id="base-freight" value="40.00" step="0.01" min="0" class="w-full p-2 border rounded">
                    </div>
                    <div class="flex-1">
                        <label class="block text-sm font-semibold mb-1">空驶保底(元)</label>
                        <input type="number" id="base-empty" value="40.00" step="0.01" min="0" class="w-full p-2 border rounded">
                    </div>
                </div>
                <div class="flex gap-2 mb-2">
                    <button id="confirm-rule" class="px-3 py-1 bg-green-500 text-white rounded text-sm">确认当前规则</button>
                    <button id="add-rule" class="px-3 py-1 bg-blue-500 text-white rounded text-sm">添加区间</button>
                    <button id="del-rule" class="px-3 py-1 bg-red-500 text-white rounded text-sm">删除区间</button>
                </div>
                <div id="tip-container" class="mb-2"></div>
                <div class="overflow-x-auto">
                    <table class="min-w-full border-collapse text-sm">
                        <thead><tr class="bg-gray-50"><<th class="border p-1 text-left">区间结束(km)</</th><<th class="border p-1 text-left">载货单价(元/km)</</th><<th class="border p-1 text-left">空驶单价(元/km)</</th></tr></thead>
                        <tbody id="rule-table"></tbody>
                    </table>
                </div>
            </div>
        </div>
        <div class="bg-white rounded-lg shadow p-4">
            <h3 class="font-bold mb-3">单趟计提计算</h3>
            <div class="flex gap-3 mb-3">
                <div class="flex-1 border p-2 rounded"><div class="text-sm text-gray-600">载货计提</div><div id="freight-result" class="text-xl font-bold text-green-600">¥ 0.00</div></div>
                <div class="flex-1 border p-2 rounded"><div class="text-sm text-gray-600">空驶计提</div><div id="empty-result" class="text-xl font-bold text-blue-600">¥ 0.00</div></div>
            </div>
            <div>
                <label class="block text-sm font-semibold mb-1">公里数（如12.5）</label>
                <input type="number" id="distance" step="0.1" min="0" placeholder="输入公里数" class="w-full p-2 border rounded">
                <button id="calc-btn" class="mt-2 w-full py-2 bg-blue-600 text-white rounded">计算计提</button>
            </div>
        </div>
    </div>
    <script>
        const DEFAULT_SETTINGS = {
            rules: [
                { endKm: 10, freightRate: 1.6, emptyRate: 1.0 },
                { endKm: 20, freightRate: 1.5, emptyRate: 0.8 },
                { endKm: 40, freightRate: 1.2, emptyRate: 0.5 },
                { endKm: 60, freightRate: 1.0, emptyRate: 0.3 },
                { endKm: 100, freightRate: 0.8, emptyRate: 0.1 },
                { endKm: 200, freightRate: 0.6, emptyRate: 0.05 },
                { endKm: 500, freightRate: 0.3, emptyRate: 0.03 },
                { endKm: Infinity, freightRate: 0.15, emptyRate: 0.01 }
            ],
            baseFreight: 40.00, baseEmpty: 40.00
        };
        let tempRules = [...DEFAULT_SETTINGS.rules];
        let activeRules = JSON.parse(JSON.stringify(tempRules));
        let baseFreight = DEFAULT_SETTINGS.baseFreight;
        let baseEmpty = DEFAULT_SETTINGS.baseEmpty;
        const dom = {
            settingsHeader: document.getElementById('settings-header'),
            settingsContent: document.getElementById('settings-content'),
            settingsIcon: document.getElementById('settings-icon'),
            ruleTable: document.getElementById('rule-table'),
            confirmRuleBtn: document.getElementById('confirm-rule'),
            addRuleBtn: document.getElementById('add-rule'),
            delRuleBtn: document.getElementById('del-rule'),
            tipContainer: document.getElementById('tip-container'),
            baseFreight: document.getElementById('base-freight'),
            baseEmpty: document.getElementById('base-empty'),
            distance: document.getElementById('distance'),
            calcBtn: document.getElementById('calc-btn'),
            freightResult: document.getElementById('freight-result'),
            emptyResult: document.getElementById('empty-result')
        };
        function showTip(type, text){
            dom.tipContainer.innerHTML = '';
            const tip = document.createElement('p');
            tip.className = type === 'success' ? 'success-tip' : 'error-tip';
            tip.innerHTML = `${type === 'success' ? '✅' : '⚠️'} ${text}`;
            dom.tipContainer.appendChild(tip);
            if (type === 'success') setTimeout(() => dom.tipContainer.innerHTML = '', 3000);
        }
        function renderTable(){
            dom.ruleTable.innerHTML = '';
            tempRules.forEach((rule, idx) => {
                const tr = document.createElement('tr');
                tr.className = idx % 2 === 0 ? 'bg-white' : 'bg-gray-50';
                tr.innerHTML = `
                    <td class="border p-1"><input type="text" value="${rule.endKm === Infinity ? '无限' : rule.endKm}" class="w-full p-1 border rounded" oninput="updateRule(${idx}, 'endKm', this.value)"></td>
                    <td class="border p-1"><input type="number" step="0.01" min="0" value="${rule.freightRate}" class="w-full p-1 border rounded" oninput="updateRule(${idx}, 'freightRate', this.value)"></td>
                    <td class="border p-1"><input type="number" step="0.01" min="0" value="${rule.emptyRate}" class="w-full p-1 border rounded" oninput="updateRule(${idx}, 'emptyRate', this.value)"></td>
                `;
                dom.ruleTable.appendChild(tr);
            });
        }
        window.updateRule = function(idx, key, value){
            if (idx >= tempRules.length) return;
            if (key === 'endKm') tempRules[idx].endKm = (value === '无限' || value === '') ? Infinity : Math.max(0, parseFloat(value) || 0);
            else tempRules[idx][key] = Math.max(0, parseFloat(value) || 0);
            dom.tipContainer.innerHTML = '';
        };
        function checkRule(){
            const validRules = tempRules.filter(r => r.endKm !== Infinity);
            for (let i = 1; i < validRules.length; i++) if (validRules[i].endKm <= validRules[i-1].endKm) return { ok: false, tip: '区间需递增（如10→20→40）' };
            for (const r of tempRules) if (r.freightRate < 0 || r.emptyRate < 0) return { ok: false, tip: '单价不能为负数' };
            return { ok: true, tip: '新规则已生效' };
        }
        function calcTotal(km, rules, base){
            const validKm = isNaN(km) || km < 0 ? 0 : parseFloat(km.toFixed(1));
            if (validKm === 0) return Math.max(0, base);
            let total = 0, prevEnd = 0;
            for (const r of rules) {
                const currEnd = r.endKm;
                const segmentKm = currEnd === Infinity ? (validKm > prevEnd ? validKm - prevEnd : 0) : (validKm <= currEnd ? validKm - prevEnd : currEnd - prevEnd);
                total += segmentKm * r.freightRate;
                prevEnd = currEnd;
                if (validKm <= currEnd) break;
            }
            return Math.max(total, base);
        }
        const STORAGE_KEY = 'ladderCalculatorSettings';
        function saveSettings(){ localStorage.setItem(STORAGE_KEY, JSON.stringify({ rules: tempRules, baseFreight, baseEmpty })); }
        function loadSettings(){
            const savedSettings = localStorage.getItem(STORAGE_KEY);
            if (savedSettings) try {
                const parsed = JSON.parse(savedSettings);
                if (Array.isArray(parsed.rules) && parsed.rules.length > 0) { tempRules = parsed.rules; activeRules = JSON.parse(JSON.stringify(tempRules)); }
                if (typeof parsed.baseFreight === 'number') baseFreight = parsed.baseFreight;
                if (typeof parsed.baseEmpty === 'number') baseEmpty = parsed.baseEmpty;
            } catch (e) { console.error("加载本地存储失败，使用默认设置。", e); }
            dom.baseFreight.value = baseFreight;
            dom.baseEmpty.value = baseEmpty;
        }
        dom.settingsHeader.addEventListener('click', () => {
            const isHidden = dom.settingsContent.classList.toggle('hidden');
            dom.settingsIcon.textContent = isHidden ? '+' : '-';
        });
        dom.confirmRuleBtn.addEventListener('click', () => {
            baseFreight = Math.max(0, parseFloat(dom.baseFreight.value) || 0);
            baseEmpty = Math.max(0, parseFloat(dom.baseEmpty.value) || 0);
            const res = checkRule();
            if (res.ok) { activeRules = JSON.parse(JSON.stringify(tempRules)); saveSettings(); showTip('success', res.tip); }
            else showTip('error', res.tip);
        });
        dom.addRuleBtn.addEventListener('click', () => {
            const last = tempRules[tempRules.length - 1];
            const newEnd = last.endKm === Infinity ? 1000 : last.endKm + 100;
            tempRules.splice(tempRules.length - 1, 0, { endKm: newEnd, freightRate: 0, emptyRate: 0 });
            renderTable(); dom.tipContainer.innerHTML = '';
        });
        dom.delRuleBtn.addEventListener('click', () => {
            if (tempRules.length <= 2) { showTip('error', '至少保留2个区间（含“无限”）'); return; }
            tempRules.splice(tempRules.length - 2, 1); renderTable(); dom.tipContainer.innerHTML = '';
        });
        dom.calcBtn.addEventListener('click', () => {
            const km = parseFloat(dom.distance.value);
            const freight = calcTotal(km, activeRules, baseFreight);
            const emptyRules = activeRules.map(r => ({ ...r, freightRate: r.emptyRate }));
            const empty = calcTotal(km, emptyRules, baseEmpty);
            dom.freightResult.textContent = `¥ ${freight.toFixed(2)}`;
            dom.emptyResult.textContent = `¥ ${empty.toFixed(2)}`;
        });
        function init(){ loadSettings(); renderTable(); }
        init();
    </script>
</body>
</html>
